package com.kamistoat.meimeimall.meimeimallware.listener;

import com.kamistoat.meimeimall.common.To.wareTo.LockOrderWareTo;
import com.kamistoat.meimeimall.common.runTimeFunc.RunTimeLog;
import com.kamistoat.meimeimall.meimeimallware.entity.WareOrderTaskEntity;
import com.kamistoat.meimeimall.meimeimallware.service.WareSkuService;
import com.kamistoat.meimeimall.meimeimallware.vo.WareOrderTaskAndDetailVo;
import com.rabbitmq.client.Channel;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;

@Service
public class StockTaskOnCreateListener {
    protected Logger logger = LoggerFactory.getLogger(StockTaskOnCreateListener.class);

    @Autowired
    WareSkuService wareSkuService;
    @Autowired
    RedissonClient redissonClient;

    /**
     * 消费创建订单时的库存真正扣除，执行订单-库存工单
     *
     * @param message
     * @param lockOrderWareTo 订单-库存工单
     * @param channel
     */
    @RabbitListener(queues = "stock.task.onCreate.queue")
    public void handleSeckillNewStock(Message message, WareOrderTaskAndDetailVo wareOrderTaskAndDetailVo, Channel channel) throws IOException {
        logger.info("执行新订单" + wareOrderTaskAndDetailVo.getOrderSn() + "的库存扣减任务");
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        // 抢占该订单-库存工单对应的分布式锁。
        // 防止消费者进度太慢，当消费到的时候，该工单正在被其他状态操作
        RLock wareTaskLock = redissonClient.getLock("stock::taskLock::{" + wareOrderTaskAndDetailVo.getId() + "}");
        try {
            boolean tryLock = wareTaskLock.tryLock();
            if (!tryLock) {
                channel.basicReject(deliveryTag, false);
            } else {
                // 幂等消费在方法中完成，不在这里进行。
                wareSkuService.lockWareOnCreate(wareOrderTaskAndDetailVo);
                channel.basicAck(deliveryTag, false);
            }
        } catch (Exception e) {
            channel.basicReject(deliveryTag, false);
        } finally {
            wareTaskLock.unlock();
        }
    }
}
